# import copy
from datetime import datetime
from PyQt5.QtCore import Qt, QAbstractTableModel, QModelIndex
from PyQt5.QtWidgets import QTableView, QMenu, QInputDialog, QErrorMessage, QDialog, QDialogButtonBox, QVBoxLayout
import traceback
import logging
from PyQt5 import QtCore
from MyTableView import MyTableView
class MyListModel(QAbstractTableModel):
    def __init__(self,  parent=None):
        QAbstractTableModel.__init__(self, parent)
        self.objects = []
        self.properties =  []
    def getObject(self, index):
        if not index.isValid():
            return None
        objectIndex = index.row()
        try:
            return self.objects[objectIndex]
        except IndexError:
            return None
    def getObjectRow(self, row):
        try:
            return self.objects[row]
        except IndexError:
            return None
    def getProperty(self, index):
        if not index.isValid():
            return None
        propertyIndex = index.column()
        try:
            return self.properties[propertyIndex]
        except IndexError:
            return None

    def rowCount(self, parent=None, *args, **kwargs):
        return len(self.objects)

    def columnCount(self, parent=None, *args, **kwargs):
        return len(self.properties)

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid(): 
            return None
        # elif role != Qt.DisplayRole: 
        #     return None
        obj = self.getObject(index)
        prop = self.getProperty(index)
        if (obj is None) or (prop is None):
            return None
        try:
            if role in [Qt.DisplayRole, Qt.EditRole]:
                return obj[index.column()]
        except:
            return None
        return None

    def setData(self, index, value, role=Qt.EditRole):
        if not index.isValid():
            logging.info("index invalid")
            return False
        obj = self.getObject(index)
        prop = self.getProperty(index)
        if (obj is None) or (prop is None):
            logging.info("obj is None or prop is None")
            return None
        try:
            if role == Qt.EditRole:
                logging.info(type(value))
                # setAttrRecursive(obj, prop['attr'], value)
                obj[index.column()]=value
                return True
        except:
            traceback.print_exc()
            return False
        return False

    def flags(self, index):
        flags = QAbstractTableModel.flags(self, index)
        if not index.isValid():
            return flags
        prop = self.getProperty(index)
        if prop is None:
            return flags
        flags |= Qt.ItemIsEnabled
        flags |= Qt.ItemIsSelectable
        mode = prop.get('mode', "Read/Write")
        if "Write" in mode:
            flags |= Qt.ItemIsEditable
        return flags
    def headerData(self, col, orientation, role= Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            if col<len(self.properties):
                p=self.properties[col]
                if p!=None:
                    return QtCore.QVariant(p["header"])
                else:
                    return QtCore.QVariant()
        return QtCore.QVariant()

    def setObjects(self,objects,properties):
        self.beginResetModel()
        self.objects=objects
        self.properties=properties
        self.endResetModel()

    def clearObjects(self):
        if len(self.objects):
            self.beginResetModel()
            del self.objects[:]
            self.endResetModel()

    def sort(self, Ncol, order):
        """Sort table by given column number.
        """
        self.layoutAboutToBeChanged.emit()#SIGNAL("layoutAboutToBeChanged()"))
        print(Ncol)
        # self.objects =sorted(self.objects, key=operator.itemgetter(Ncol))        
        try:
            self.objects =sorted(self.objects,key=lambda x: x[self.properties[Ncol]["attr"]])
        except TypeError:
            pass
        if order == Qt.DescendingOrder:
            self.objects.reverse()
        self.layoutChanged.emit()#SIGNAL("layoutChanged()"))

class MyListView(MyTableView):
    def __init__(self, model, parent=None):
        super().__init__(parent)
        self.setSortingEnabled(True)
    def setModel(self, model):
        QTableView.setModel(self, model)
        for i, prop in enumerate(model.properties):
            # logging.info([i,prop,prop.get('visible',True)])
            if prop.get('visible',True)==True:
                # logging.info("show")
                self.setColumnHidden(i,False)
            else:
                # logging.info("hide")
                self.setColumnHidden(i,True)
            width=prop.get('width',100)
            self.setColumnWidth(i,width)
            # self.setItemDelegateForColumn(i, prop.get('delegate'))

    def selectedRows(self):
        selectedIndexes = self.selectionModel().selection().indexes()
        rows = set()
        for index in selectedIndexes:
            rows.add(index.row())
        return sorted(list(rows))

    def selectedColumns(self):
        selectedIndexes = self.selectionModel().selection().indexes()
        columns = set()
        for index in selectedIndexes:
            columns.add(index.column())
        return sorted(list(columns))

    def clearObjects(self):
        self.model().clearObjects()

if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication

    # We'll create a table model/view for a list of these objects.
        # Create the QApplication.
    app = QApplication(sys.argv)

    # Create our object list.
    a = ["obj A", "a str", 3, 0.042, True]
    b = ["obj B", "b str", -1, -10.069, False]
    objects = [a, b]

    # Specify the properties to display in the model/view.
    properties = [
        {'width':90,'visible':True,'attr': 0,           'header': "Read Only Name",      'mode': "Read Only"},
        {'attr': 1,       'header': "String"},
        {'attr': 2,       'header': "Integer"},
        {'attr': 3,     'header': "Float"},
        {'attr': 4,      'header': "Bool"}]

    # Print property names/values/types prior to editing.
    print("---------- BEFORE EDITING ----------")
    print(objects)
    # Create the model/view.
    model = MyListModel()
    view = MyListView(model)

    model.setObjects(objects,properties)
    view.setModel(model)
    # Show the model/view and run the application.
    view.setAttribute(Qt.WA_DeleteOnClose)
    view.show()
    status = app.exec()

    # Print property names/values/types post editing.
    print("---------- AFTER EDITING ----------")
    print(objects)
    sys.exit(status)
